using System;
using System.Net;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Text;
using Microsoft.MSE.Catalog.Module.Configuration;
using Microsoft.Uddi;
using Microsoft.Uddi.TModels;
using Microsoft.Uddi.Businesses;
using Microsoft.Uddi.Services;
using Microsoft.MSE.Catalog.Contracts;

namespace Microsoft.MSE.Catalog.Module
{
    class UddiPublisher : IDisposable 
    {
        private UddiConnection uddiConnection;
        private string businessKey;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="uddiInformation"></param>
        public UddiPublisher(ServiceCatalogUddi uddiInformation)
        {
            uddiConnection = new UddiConnection();
            uddiConnection.InquireUrl = uddiInformation.UddiInquireUrl;
            uddiConnection.PublishUrl = uddiInformation.UddiPublishUrl;
            uddiConnection.Username = uddiInformation.UddiUserName;
            uddiConnection.Password = uddiInformation.UddiPassword;
            
            if (uddiInformation.UddiAuthenticationScheme == AuthnticationScheme.UDDI)
                uddiConnection.AuthenticationMode = AuthenticationMode.UddiAuthentication;
            else
                uddiConnection.AuthenticationMode = AuthenticationMode.WindowsAuthentication;

            businessKey = uddiInformation.BusinessKey;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public Endpoint PublishEndpointToUddi(Endpoint endPoint, RuntimeServer runtimeServer)
        {
            EndpointAssociatedUddi endpointAssociatedUddi = new EndpointAssociatedUddi();

            try
            {
                endpointAssociatedUddi.EndpointID = endPoint.ID;
                endpointAssociatedUddi.RuntimeServerID = runtimeServer.ID;

                // Create TModel
                SaveTModel saveTModel = new SaveTModel();
                TModel tModel = null;
                if (string.IsNullOrEmpty(endPoint.NamespaceURI) == false)
                    tModel = new TModel(endPoint.NamespaceURI);
                else
                    tModel = new TModel("http://tempuri.org");

                tModel.Descriptions.Add(endPoint.Description == null ? "Please add description" : endPoint.Description, "en");
                // NZ TODO
                // Check if the Address is of type HTTP/HTTPS
                // Otherwise leave this blank
                Uri serviceUri = Data.Endpoint.GetEndpointServiceUri(endPoint, runtimeServer);

                tModel.OverviewDoc.OverviewUrl = serviceUri.ToString() + "?wsdl";
                saveTModel.TModels.Add(tModel);
                saveTModel.TModels[0].CategoryBag.Add("uuid:c1acf26d-9672-4404-9d70-39b756e62ab4", "wsdlSpec", "uddi-org:types");

                TModelDetail tModelDetail = saveTModel.Send(uddiConnection);

                // Save the Service, Binding Template and TModel Instance 
                SaveService saveService = new SaveService();

                // Create a Service
                BusinessService businessService = new BusinessService(string.IsNullOrEmpty(endPoint.ServiceName) ? "Please add name" : endPoint.ServiceName);
                businessService.Descriptions.Add(string.IsNullOrEmpty(endPoint.Description) ? "Please add description" : endPoint.Description);
                businessService.BusinessKey = businessKey;
                saveService.BusinessServices.Add(businessService);

                // Create a binding template.
                BindingTemplate bindingTemplate = new BindingTemplate();
                bindingTemplate.AccessPoint.Text = serviceUri.ToString();
                if (serviceUri.ToString().StartsWith("https://",StringComparison.CurrentCultureIgnoreCase) == true)
                    bindingTemplate.AccessPoint.UrlType = Microsoft.Uddi.UrlType.Https;
                else
                    bindingTemplate.AccessPoint.UrlType = Microsoft.Uddi.UrlType.Http;
                businessService.BindingTemplates.Add(bindingTemplate);

                // Create the tModel instance information.
                TModelInstanceInfo tModelInstanceInfo = new TModelInstanceInfo();
                tModelInstanceInfo.Descriptions.Add(string.IsNullOrEmpty(endPoint.Description) ? "Please add description" : endPoint.Description, "en");
                tModelInstanceInfo.TModelKey = tModelDetail.TModels[0].TModelKey;
                businessService.BindingTemplates[0].TModelInstanceInfos.Add(tModelInstanceInfo);

                ServiceDetail serviceDetail = saveService.Send(uddiConnection);

                endpointAssociatedUddi.ServiceKey = serviceDetail.BusinessServices[0].ServiceKey;
                endpointAssociatedUddi.TModelKey = tModelDetail.TModels[0].TModelKey;
                endpointAssociatedUddi.BindingKey = serviceDetail.BusinessServices[0].BindingTemplates[0].BindingKey;
                endpointAssociatedUddi.WsdlUrl = serviceUri.ToString() + "?wsdl";
                endpointAssociatedUddi.BindingUrl = serviceUri.ToString();

                endPoint.UddiAssociations.Add(endpointAssociatedUddi);
            }
            catch (UddiException ue)
            {
               throw new ApplicationException("A UDDI specific error occurred while publishing Endpoint data to UDDI",ue);
            }
            catch (Exception e)
            {
                throw new ApplicationException("A general error occurred while publishing Endpoint data to UDDI", e);
            }
            return endPoint;
        }

        public Endpoint UpdateEndpointToUddi(Endpoint endPoint, RuntimeServer runtimeServer)
        {
            EndpointAssociatedUddi endpointAssociatedUddi = null;
            try
            {
                if (endPoint.UddiAssociations != null && endPoint.UddiAssociations.Count > 0)
                {
                    endpointAssociatedUddi = Data.Endpoint.GetUddiAssociation(endPoint, runtimeServer);
                    if (endpointAssociatedUddi != null)
                    {
                        Uri serviceUri = Data.Endpoint.GetEndpointServiceUri(endPoint, runtimeServer);

                        // Get Binding Detail, update Access Point info and save it back to UDDI
                        GetBindingDetail getBindingDetail = new GetBindingDetail(endpointAssociatedUddi.BindingKey);
                        BindingDetail bindingDetail = null;
                        try
                        {
                            bindingDetail = getBindingDetail.Send(uddiConnection);
                        }
                        catch (InvalidKeyPassedException ikpe)
                        {
                            throw new ApplicationException(string.Format("Binding Key [{0}] does not exist in UDDI", endpointAssociatedUddi.BindingKey), ikpe);
                        }
                        catch (Exception ex)
                        {
                            throw;
                        }

                        BindingTemplate bindingTemplate = bindingDetail.BindingTemplates[0];
                        bindingTemplate.AccessPoint.Text = serviceUri.ToString();
                        if (serviceUri.ToString().StartsWith("https://", StringComparison.CurrentCultureIgnoreCase) == true)
                            bindingTemplate.AccessPoint.UrlType = Microsoft.Uddi.UrlType.Https;
                        else
                            bindingTemplate.AccessPoint.UrlType = Microsoft.Uddi.UrlType.Http;
                        SaveBinding saveBinding = new SaveBinding(bindingTemplate);
                        saveBinding.Send(uddiConnection);

                        // Get TModel, update WSDL info and save it back to UDDI
                        GetTModelDetail getTModelDetail = new GetTModelDetail(endpointAssociatedUddi.TModelKey);
                        TModelDetail tModelDetail = null;
                        try
                        {
                            tModelDetail = getTModelDetail.Send(uddiConnection);
                        }
                        catch (InvalidKeyPassedException ikpe)
                        {
                            throw new ApplicationException(string.Format("TModel Key [{0}] does not exist in UDDI", endpointAssociatedUddi.TModelKey), ikpe);
                        }
                        catch (Exception ex)
                        {
                            throw;
                        }
                        TModel tModel = tModelDetail.TModels[0];
                        tModel.OverviewDoc.OverviewUrl = serviceUri.ToString() + "?wsdl";

                        SaveTModel saveTModel = new SaveTModel(tModel);
                        saveTModel.Send(uddiConnection);

                        endpointAssociatedUddi.WsdlUrl = serviceUri.ToString() + "?wsdl";
                        endpointAssociatedUddi.BindingUrl = serviceUri.ToString();
                    }
                    else
                    {
                        TraceHelper.TraceWarning("Unable to find Uddi association for EndPoint [{0}] and RuntimeServer [{1}]", endPoint.ID, runtimeServer.ID);
                    }
                }
            }
            catch (UddiException ue)
            {
                throw new ApplicationException("A UDDI specific error occurred while updating Endpoint data to UDDI", ue);
            }
            catch (Exception e)
            {
                throw new ApplicationException("A general error occurred while updating Endpoint data to UDDI", e);
            }
            return endPoint;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="uddiService"></param>
        public void RemoveEndpointFromUddi(Endpoint endPoint, RuntimeServer runtimeServer)
        {
            try
            {
                if (endPoint.UddiAssociations != null && endPoint.UddiAssociations.Count > 0)
                {
                    EndpointAssociatedUddi endpointAssociatedUddi = Data.Endpoint.GetUddiAssociation(endPoint, runtimeServer);
                    if (endpointAssociatedUddi != null)
                    {
                        // Delete Service
                        DeleteService deleteService = new DeleteService(endpointAssociatedUddi.ServiceKey);
                        deleteService.Send(uddiConnection);

                        // Delete TModel
                        DeleteTModel deleteTModel = new DeleteTModel(endpointAssociatedUddi.TModelKey);
                        deleteTModel.Send(uddiConnection);

                        // Remove it from Collection
                        endPoint.UddiAssociations.Remove(endpointAssociatedUddi);
                    }
                    else
                    {
                        TraceHelper.TraceWarning("Unable to find Uddi association for EndPoint [{0}] and RuntimeServer [{1}]", endPoint.ID, runtimeServer.ID);
                    }
                }
            }
            catch (UddiException ue)
            {
                throw new ApplicationException("A UDDI specific error occurred while removing Endpoint data from UDDI", ue);
            }
            catch (Exception e)
            {
                throw new ApplicationException("A general error occurred while removing Endpoint data from UDDI", e);
            }
        }
        public void Dispose()
        {
            if (uddiConnection != null)
                uddiConnection.Close();
        }

    }
}
